/** @noSelfInFile **/
import {UnitModel} from "../../../adapterModel/model3/UnitModel";
import {ItemModel} from "../../../adapterModel/model3/ItemModel";
import {RectModel} from "../../../adapterModel/model2/RectModel";
import {LocModel} from "../../../base/LocModel";
import {PlayerModel} from "../../../adapterModel/model4/PlayerModel";
import {IModelAdapter, modelCenter, ModelType} from "../../adapterInterface/model5/IModelFactory";
import {GlobalModel} from "../../../adapterModel/model1/GlobalModel";
import {RectRecord} from "../model2/RectAdapter";
import Configer from "../../../config/Configer";
import {ConfigKey} from "../../../../../constant/ConfigConstant";


/**
 * 对象池
 * 对象复用，主要因为魔兽lua中使用jass创建的单位无法自动销毁
 */
class ObjectPool<T> {
    //对象
    objects: T[] = [];
    //对象是否空闲
    objectIdleStatus: boolean[] = [];
    lastBorrowObjectIndex: number = -1;
    private create: () => T = null;
    private returnCallBack: (obj: T) => boolean | void = null;
    private maxTotal: number = 1000000;

    /**
     *
     * @param create = 创建对象的
     * @param returnCallBack
     */
    constructor(create: () => T, returnCallBack: (obj: T) => boolean | void = null) {
        this.create = () => { return create() };
        this.returnCallBack = (obj: T) => { return returnCallBack(obj) };
    }

    /**
     * 获取一个对象
     * @param obj
     */
    public borrowObject(): T {
        for (let i = 0; i < this.maxTotal; i++) {
            if (this.objectIdleStatus[i] == true) {
                this.lastBorrowObjectIndex = i;
                this.objectIdleStatus[i] = false;
                return this.objects[i];
            } else if (this.objects[i] == null) {
                this.objects[i] = this.create();
                this.lastBorrowObjectIndex = i;
                this.objectIdleStatus[i] = false;
                return this.objects[i];
            }

        }
        //超过最大数量
        return null;
    }


    /**
     * 返还一个对象
     * @param obj
     */
    public returnObject(obj: T): boolean {
        let isIdle = true;
        if (this.returnCallBack) {
            let flag = this.returnCallBack(obj);
            if (flag != null) {
                isIdle = flag as boolean;
            }
        }
        for (let i = 0; i < this.maxTotal; i++) {
            if (obj == this.objects[i]) {
                this.objectIdleStatus[i] = isIdle;
                return true
            }
        }
        return false;
    }


}

// jass转lua闭包处理
class GroupUtil {
    /**
     * 单位组 对象池
     */
    static groupObjectPool: ObjectPool<group> = new ObjectPool<group>(() => {
        if (isAsync) {
            log.errorWithTraceBack("不能在异步操作中创建handle!")
            return null;
        }
        return CreateGroup()
    }, g => {
        GroupClear(g);
    });

    static _temp_callBack = null;
    static _SL_EnumItemsInRectFunc = function (this: void) {
        GroupUtil._temp_callBack();
    }

    /**
     * 遍历完会清空单位组
     * @param whichGroup
     * @param callback
     */
    static for(whichGroup: group, callback: (unit: unit) => void) {
        for (let i = 0; i <= 1000000; i++) {
            let unitHandle = FirstOfGroup(whichGroup)
            if (!IsHandle(unitHandle)) {
                break
            }
            callback(unitHandle)
            GroupRemoveUnit(whichGroup, unitHandle)
        }
        GroupUtil.groupObjectPool.returnObject(whichGroup);
    }
}

const itemSlopMap = [];

export class ModelAdapter implements IModelAdapter {
    mapPlayerSelected(player: PlayerModel, fun: (unit: UnitModel) => void): void {
        const group = GetUnitsSelectedAll(player.handle);

        GroupUtil.for(group, (unit) => {
            const handleId = GlobalModel.getHandleId(unit);
            const unitModel = modelCenter.getModel(handleId, ModelType.unit) as UnitModel;
            if (unitModel) {
                fun(unitModel);
            }
        })
    }

    mapItemsInRange(loc: LocModel, radius: number, callBack: (item: ItemModel) => void): void {
        const rect = GetRectFromCircleBJ(Location(loc.x, loc.y), radius);
        if (GroupUtil._temp_callBack != null) { //已在使用中
            log.errorWithTraceBack("不能在此函数回调参数里 再使用此函数!")
            return
        }
        const tempCallBack = function () {
            const item = GetEnumItem()
            const handleId = GlobalModel.getHandleId(item);
            const itemModel = modelCenter.getModel(handleId, ModelType.item) as ItemModel;
            if (itemModel) {
                callBack(itemModel);
            }
        }
        GroupUtil._temp_callBack = tempCallBack;
        EnumItemsInRect(rect, null, GroupUtil._SL_EnumItemsInRectFunc);
        //使用命名函数 减少闭包交互
        GroupUtil._temp_callBack = null;//空闲状态
    }

    mapItemsInRect(rect: RectModel, callBack: (item: ItemModel) => void): void {
        if (GroupUtil._temp_callBack != null) { //已在使用中
            log.errorWithTraceBack("不能在此函数回调参数里 再使用此函数!")
            return
        }
        const tempCallBack = () => {
            const item = GetEnumItem()
            const handleId = GlobalModel.getHandleId(item);
            const itemModel = modelCenter.getModel(handleId, ModelType.item) as ItemModel;
            if (itemModel) {
                callBack(itemModel);
            }
        }
        GroupUtil._temp_callBack = tempCallBack;
        rect.enumItems(GroupUtil._SL_EnumItemsInRectFunc)
        //使用命名函数 减少闭包交互
        GroupUtil._temp_callBack = null;//空闲状态
    }

    mapUnitInRange(loc: LocModel, radius: number, fun: (unit: UnitModel) => void): void {
        let group = GroupUtil.groupObjectPool.borrowObject();
        GroupEnumUnitsInRange(group, loc.x, loc.y, radius, null);
        GroupUtil.for(group, (unit) => {
            const handleId = GlobalModel.getHandleId(unit);
            const unitModel = modelCenter.getModel(handleId, ModelType.unit) as UnitModel;
            if (unitModel) {
                fun(unitModel)
            }
        })
        GroupUtil.groupObjectPool.returnObject(group);
    }

    mapUnitInRect(rect: RectModel, fun: (unitModel: UnitModel) => void): void {
        const handle: RectRecord = rect.handle;
        const group = GetUnitsInRectAll(handle?.rect);
        GroupUtil.for(group, (unit) => {
            const handleId = GlobalModel.getHandleId(unit);
            const unitModel = modelCenter.getModel(handleId, ModelType.unit) as UnitModel;
            if (unitModel) {
                fun(unitModel);
            }
        })
    }

    mapUnitItems(unit: UnitModel, fun: (item: ItemModel, index: number) => any): void {
        const maxNum = Configer.getConfig(ConfigKey.maxItemSlot)
        for (let i = 0; i < maxNum; i++) {
            let item = UnitItemInSlot(unit.handle, i);
            const handleId = GlobalModel.getHandleId(item);
            const itemModel = modelCenter.getModel(handleId, ModelType.item) as ItemModel;
            const index = i;
            if (itemModel) {
            } else {
                continue
            }
            const ret = fun(itemModel, index);
            if (ret) {
                return;
            }
        }
    }

    rectContainsUnit(rect: RectModel, unit: UnitModel): boolean {
        const handle: RectRecord = rect.handle;
        return RectContainsUnit(handle.rect, unit.handle)
    }

    initRectUnit(rect: RectModel, fun: (unit: any) => UnitModel): UnitModel[] {
        const handle: RectRecord = rect.handle;
        const group = GetUnitsInRectAll(handle.rect)
        const units: UnitModel[] = []
        GroupUtil.for(group, (unit) => {
            const tempUnit = fun(unit);
            if (tempUnit) {
                units.push(tempUnit);
            }
        })
        return units;
    }
}
